using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;


namespace InControl {
    public sealed class AutoDiscover : Attribute {}

    public class UnityInputDeviceProfile {
        public string Name { get; protected set; }
        public string Meta { get; protected set; }

        public InputControlMapping[] AnalogMappings { get; protected set; }
        public InputControlMapping[] ButtonMappings { get; protected set; }

        protected string[] SupportedPlatforms;
        protected string[] JoystickNames;
        protected string[] JoystickRegex;

        protected string LastResortRegex;

        public VersionInfo MinUnityVersion { get; protected set; }
        public VersionInfo MaxUnityVersion { get; protected set; }

        static HashSet<Type> hideList = new HashSet<Type>();

        float sensitivity;
        float lowerDeadZone;
        float upperDeadZone;


        public UnityInputDeviceProfile() {
            Name = "";
            Meta = "";

            sensitivity = 1.0f;
            lowerDeadZone = 0.2f;
            upperDeadZone = 0.9f;

            AnalogMappings = new InputControlMapping[0];
            ButtonMappings = new InputControlMapping[0];

            MinUnityVersion = new VersionInfo(3);
            MaxUnityVersion = new VersionInfo(2018);
        }


        public float Sensitivity {
            get { return sensitivity; }
            protected set { sensitivity = Mathf.Clamp01(value); }
        }


        public float LowerDeadZone {
            get { return lowerDeadZone; }
            protected set { lowerDeadZone = Mathf.Clamp01(value); }
        }


        public float UpperDeadZone {
            get { return upperDeadZone; }
            protected set { upperDeadZone = Mathf.Clamp01(value); }
        }


        public bool IsSupportedOnThisPlatform {
            get {
                if (!IsSupportedOnThisVersionOfUnity) {
                    return false;
                }

                if (SupportedPlatforms == null || SupportedPlatforms.Length == 0) {
                    return true;
                }

                foreach (var platform in SupportedPlatforms) {
                    if (InputManager.Platform.Contains(platform.ToUpper())) {
                        return true;
                    }
                }

                return false;
            }
        }


        public bool IsSupportedOnThisVersionOfUnity {
            get {
                // var unityVersion = VersionInfo.UnityVersion();
                // return unityVersion >= MinUnityVersion && unityVersion <= MaxUnityVersion;
                return true; // HACK
            }
        }


        public bool IsJoystick {
            get {
                return (LastResortRegex != null) ||
                (JoystickNames != null && JoystickNames.Length > 0) ||
                (JoystickRegex != null && JoystickRegex.Length > 0);
            }
        }


        public bool IsNotJoystick {
            get { return !IsJoystick; }
        }


        public bool HasJoystickName(string joystickName) {
            if (IsNotJoystick) {
                return false;
            }

            if (JoystickNames != null) {
                if (JoystickNames.Contains(joystickName, StringComparer.OrdinalIgnoreCase)) {
                    return true;
                }
            }

            if (JoystickRegex != null) {
                for (int i = 0; i < JoystickRegex.Length; i++) {
                    if (Regex.IsMatch(joystickName, JoystickRegex[i], RegexOptions.IgnoreCase)) {
                        return true;
                    }
                }
            }

            return false;
        }


        public bool HasLastResortRegex(string joystickName) {
            if (IsNotJoystick) {
                return false;
            }

            if (LastResortRegex == null) {
                return false;
            }

            return Regex.IsMatch(joystickName, LastResortRegex, RegexOptions.IgnoreCase);
        }


        public bool HasJoystickOrRegexName(string joystickName) {
            return HasJoystickName(joystickName) || HasLastResortRegex(joystickName);
        }


        public static void Hide(Type type) {
            hideList.Add(type);
        }


        public bool IsHidden {
            get { return hideList.Contains(GetType()); }
        }


        public virtual bool IsKnown {
            get { return true; }
        }


        public int AnalogCount {
            get { return AnalogMappings.Length; }
        }


        public int ButtonCount {
            get { return ButtonMappings.Length; }
        }


        #region InputControlSource Helpers

        protected static InputControlSource Button(int index) {
            return new UnityButtonSource(index);
        }

        protected static InputControlSource Analog(int index) {
            return new UnityAnalogSource(index);
        }

        protected static InputControlSource KeyCodeButton(params KeyCode[] keyCodeList) {
            return new UnityKeyCodeSource(keyCodeList);
        }

        protected static InputControlSource KeyCodeComboButton(params KeyCode[] keyCodeList) {
            return new UnityKeyCodeComboSource(keyCodeList);
        }

        protected static InputControlSource KeyCodeAxis(KeyCode negativeKeyCode, KeyCode positiveKeyCode) {
            return new UnityKeyCodeAxisSource(negativeKeyCode, positiveKeyCode);
        }

        protected static InputControlSource Button0 = Button(0);
        protected static InputControlSource Button1 = Button(1);
        protected static InputControlSource Button2 = Button(2);
        protected static InputControlSource Button3 = Button(3);
        protected static InputControlSource Button4 = Button(4);
        protected static InputControlSource Button5 = Button(5);
        protected static InputControlSource Button6 = Button(6);
        protected static InputControlSource Button7 = Button(7);
        protected static InputControlSource Button8 = Button(8);
        protected static InputControlSource Button9 = Button(9);
        protected static InputControlSource Button10 = Button(10);
        protected static InputControlSource Button11 = Button(11);
        protected static InputControlSource Button12 = Button(12);
        protected static InputControlSource Button13 = Button(13);
        protected static InputControlSource Button14 = Button(14);
        protected static InputControlSource Button15 = Button(15);
        protected static InputControlSource Button16 = Button(16);
        protected static InputControlSource Button17 = Button(17);
        protected static InputControlSource Button18 = Button(18);
        protected static InputControlSource Button19 = Button(19);

        protected static InputControlSource Analog0 = Analog(0);
        protected static InputControlSource Analog1 = Analog(1);
        protected static InputControlSource Analog2 = Analog(2);
        protected static InputControlSource Analog3 = Analog(3);
        protected static InputControlSource Analog4 = Analog(4);
        protected static InputControlSource Analog5 = Analog(5);
        protected static InputControlSource Analog6 = Analog(6);
        protected static InputControlSource Analog7 = Analog(7);
        protected static InputControlSource Analog8 = Analog(8);
        protected static InputControlSource Analog9 = Analog(9);
        protected static InputControlSource Analog10 = Analog(10);
        protected static InputControlSource Analog11 = Analog(11);
        protected static InputControlSource Analog12 = Analog(12);
        protected static InputControlSource Analog13 = Analog(13);
        protected static InputControlSource Analog14 = Analog(14);
        protected static InputControlSource Analog15 = Analog(15);
        protected static InputControlSource Analog16 = Analog(16);
        protected static InputControlSource Analog17 = Analog(17);
        protected static InputControlSource Analog18 = Analog(18);
        protected static InputControlSource Analog19 = Analog(19);

        protected static InputControlSource MouseButton0 = new UnityMouseButtonSource(0);
        protected static InputControlSource MouseButton1 = new UnityMouseButtonSource(1);
        protected static InputControlSource MouseButton2 = new UnityMouseButtonSource(2);

        protected static InputControlSource MouseXAxis = new UnityMouseAxisSource("x");
        protected static InputControlSource MouseYAxis = new UnityMouseAxisSource("y");
        protected static InputControlSource MouseScrollWheel = new UnityMouseAxisSource("z");

        #endregion
    }
}

